package com.ccp.dev.form.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.db.datasource.JdbcTemplateUtil;
import com.ccp.dev.core.basic.engine.GroovyScriptEngine;
import com.ccp.dev.core.basic.page.PageList;
import com.ccp.dev.core.basic.table.BaseTableMeta;
import com.ccp.dev.core.basic.table.ColumnModel;
import com.ccp.dev.core.basic.table.IDbView;
import com.ccp.dev.core.basic.table.TableModel;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.DateFormatUtil;
import com.ccp.dev.core.util.StringPool;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.form.dao.FormDialogDao;
import com.ccp.dev.form.model.*;
import com.ccp.dev.form.table.TableMetaFactory;
import com.ccp.dev.workflow.bpmutil.ServiceUtil;
import net.sf.json.JSONObject;
import org.apache.commons.collections.map.CaseInsensitiveMap;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;

/**
 * 自定义对话框 service类
 *
 * @author zhaowj
 */
@Service
public class FormDialogService extends BaseService<FormDialog> {

    @Resource
    FormDialogDao formDialogDao;

    @Resource
    private JdbcTemplateUtil jdbcTemplateUtil;

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Value("${mybatis.configuration.database-id}")
    private String dataSourceType;

    @Resource
    private GroovyScriptEngine groovyScriptEngine;

    @Resource
    private FormFieldService formFieldService;

    @Resource
    private DataTemplateService dataTemplateService;

    @Resource
    private FormTableService formTableService;

    /**
     * 添加或更新自定义对话框
     *
     * @param formDialog 数据源对象
     * @return 记录条数
     */
    @Transactional(rollbackFor = Exception.class)
    public int addOrUpdate(FormDialog formDialog) {
        int count;
        formDialog.setDisplayfield(StringEscapeUtils.unescapeHtml4(formDialog.getDisplayfield()));
        formDialog.setResultfield(StringEscapeUtils.unescapeHtml4(formDialog.getResultfield()));
        formDialog.setConditionfield(StringEscapeUtils.unescapeHtml4(formDialog.getConditionfield()));
        formDialog.setSortfield(StringEscapeUtils.unescapeHtml4(formDialog.getSortfield()));
        if (StringUtil.isEmpty(formDialog.getId())) {
            formDialog.setId(UUIDUtils.getUUIDFor32());
            count = formDialogDao.add(formDialog);
        } else {
            count = formDialogDao.update(formDialog);
        }
        return count;
    }

    /**
     * 根据别名查询自定义对话框数量
     *
     * @param alias 自定义对话框别名
     * @param alias 自定义对话框id
     * @return 记录条数
     */
    public boolean isExistAlias(String alias, String id) {
        return formDialogDao.isExistAlias(alias, id) > 0;
    }

    /**
     * 根据别名获取对应对话框的数据
     *
     * @param bpmFormDialog 对话框别名
     * @param params        参数集合
     * @return
     * @throws Exception
     */
    public FormDialog getData(FormDialog bpmFormDialog, Map<String, Object> params) throws Exception {
        List<DialogField> displayList = bpmFormDialog.getDisplayList();
        List<DialogField> conditionList = bpmFormDialog.getConditionList();
        String objectName = bpmFormDialog.getObjname();
        Map<String, Object> map = new HashMap<>(10);
        map.put("objectName", objectName);
        map.put("displayList", displayList);
        map.put("conditionList", conditionList);
        map.put("sortList", bpmFormDialog.getSortList());
        String tenantId = ContextUtil.getCurrentUserTenantId();
        // 是否是列表
        if (bpmFormDialog.getStyle() == FormDialog.STYLE_LIST) {
            // 是否需要分页。
            if (bpmFormDialog.getNeedpage() == 1) {
                int currentPage = Integer.parseInt(params.get(FormDialog.Page).toString());
                int pageSize = Integer.parseInt(params.get(FormDialog.PageSize).toString());
                Map<String, Object> params2 = new CaseInsensitiveMap();
                params2.putAll(params);
                if (params.containsKey("sortName")) {
                    params2.put("sortField", params.get("sortName"));
                }
                if (params.containsKey("sortOrder")) {
                    params2.put("orderSeq", params.get("sortOrder"));
                }
                String sql = ServiceUtil.getSql(map, params2, "");
                if ("V_FORMDEF_TEMPLATE".equalsIgnoreCase(objectName)) {
                    StringBuilder sb = new StringBuilder(sql);
                    // 在ServiceUtil.getSql(map, params)方法中：sql = "select a.* from " + objectName + " a";
                    int index = sb.indexOf("v_formdef_template a");
                    if (index < 0) {
                        index = sb.indexOf("V_FORMDEF_TEMPLATE a");
                        index += "V_FORMDEF_TEMPLATE a".length();
                    } else {
                        index += "v_formdef_template a".length();
                    }
                    sb.insert(index + 1, " LEFT JOIN SYS_TENANT_DYNAMIC_DATA b on a.FORMDEFID = b.DATA_ID where b.TENANT_ID=" + tenantId + " ");
                    sql = sb.toString();
                }
                List list = jdbcTemplateUtil.getPage(bpmFormDialog.getDsalias(), currentPage, pageSize, sql.toLowerCase(), params2);
                //查询时候解密自定义表的数据
                decryptCustomTableField(list, bpmFormDialog.getObjname(),true);
                bpmFormDialog.setList(list);
                bpmFormDialog.setPageBean(((PageList) list).getPageBean());
            } else {
                String sql = ServiceUtil.getSql(map, params, "");
                List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
                //查询时候解密自定义表的数据
                decryptCustomTableField(list, bpmFormDialog.getObjname(),true);
                bpmFormDialog.setList(list);
            }

            //处理日期类型的数据
            String style = StringPool.DATE_FORMAT_DATE;
            for (Map<String, Object> itemMap : bpmFormDialog.getList()) {
                Set<String> keySet = itemMap.keySet();
                for (Iterator<String> it = keySet.iterator(); it.hasNext(); ) {
                    String key = it.next().toUpperCase();
                    if (itemMap.get(key) instanceof Date) {
                        if (!itemMap.get(key).toString().contains("00:00:00.0")) {
                            style = StringPool.DATE_FORMAT_DATETIME;
                        }
                        String formatStr = DateFormatUtil.format((Date) itemMap.get(key), style);
                        itemMap.put(key, formatStr);
                    }
                }
            }
        }
        return bpmFormDialog;
    }

    /**
     * 查询时候解密自定义表的数据
     * @param list 数据
     * @param tableName 表名
     * @param isKeyToUp 是否需要转成大写字母
     * @throws Exception 异常
     */
    public void decryptCustomTableField(List<Map<String, Object>> list, String tableName,boolean isKeyToUp) throws Exception {
        String queryName = tableName.replaceAll(TableModel.CUSTOMER_TABLE_PREFIX, "");
        FormTable bpmFormTable = formTableService.getByTableName(queryName.toLowerCase());
        if (null != bpmFormTable) {
            String tableId = bpmFormTable.getTableId();
            List<FormField> encryptList = formFieldService.getEncryptFieldByTableId(tableId);
            for (Map<String, Object> map : list) {
                dataTemplateService.encryptDecryptMap(map, encryptList, FormField.ISENCRYPT_NOT,isKeyToUp);
            }
        }
    }

    /**
     * 根据别名获取对话框对象
     *
     * @param alias 别名
     * @return 对话框对象
     */
    public FormDialog getByAlias(String alias) {
        return formDialogDao.getByAlias(alias);
    }

    /**
     * 返回树型结构的数据
     * @param alias 别名
     * @param params 参数
     * @param isRoot 是否是根节点
     * @return 集合
     * @throws Exception
     */
    public List getTreeData(String alias, Map<String, Object> params, boolean isRoot) throws Exception {
        FormDialog bpmFormDialog = formDialogDao.getByAlias(alias);
        JdbcTemplate template = JdbcTemplateUtil.getNewJdbcTemplate(bpmFormDialog.getDsalias());
        String sql = getTreeSql(bpmFormDialog, params, isRoot);
        List list = JdbcTemplateUtil.getNamedParameterJdbcTemplate(template).queryForList(sql, params);
        return list;
    }

    /**
     * {"id":"id","pid":"fatherId","displayName":"name"}
     *
     * @param bpmFormDialog 对话框
     * @param nodeMap nodeMap
     * @param isRoot 是否根节点
     * @return 字符串
     * @throws Exception
     */
    private String getTreeSql(FormDialog bpmFormDialog, Map<String, Object> nodeMap, boolean isRoot) throws Exception {
        String objName = bpmFormDialog.getObjname();
        List<DialogField> conditionList = bpmFormDialog.getConditionList();
        Map<String, Object> params = new HashMap<String, Object>();
        if (BeanUtils.isNotEmpty(nodeMap)) {
            params = nodeMap;
        }
        String pname = (String) nodeMap.get("pname");
        String pvalue = (String) nodeMap.get("pvalue");
        String displayField = bpmFormDialog.getDisplayfield();
        JSONObject jsonObj = JSONObject.fromObject(displayField);
        String id = jsonObj.getString("id");
        String pid = jsonObj.getString("pid");
        if (StringUtil.isNotEmpty(pname) && !isRoot) {
            DialogField pfield = getDailogField(bpmFormDialog, pname);
            if (pfield != null) {
                pfield.setCondition("=");
                conditionList.add(pfield);
                params.put(pname, pvalue);
            }
        }
        // 获取条件的SQL语句
        String sqlWhere = ServiceUtil.getWhere(conditionList, params, "");
        if (!isRoot) {
            if (sqlWhere.indexOf(pid) < 0 && StringUtil.isNotEmpty(pvalue)) {
                // 若父节点ID的值不为空，则添加查找条件
                if (StringUtil.isEmpty(sqlWhere)) {
                    sqlWhere += " where " + pid + "='" + pvalue +"'";
                } else {
                    sqlWhere += " and " + pid + "='" + pvalue +"'";
                }
            }
        } else {
            // 父节点ID的值，可为空字符串。在设置树形对话框时可对其进行赋值，以获取指定父节点的树
            pvalue = jsonObj.getString("pvalue");
            String isScript = jsonObj.getString("isScript");

            if (StringUtil.isNotEmpty(pvalue) && !"1".equals(pvalue)) {
                if ("true".equals(isScript)) {
                    // 父节点ID的值为脚本表达式
                    pvalue = groovyScriptEngine.executeObject(pvalue, null).toString();
                }
                // 若父节点ID的值不为空，则添加查找条件
                if (StringUtil.isNotEmpty(sqlWhere)) {
                    if (sqlWhere.indexOf(id) < 0) {
                        sqlWhere += " AND " + id + "='" + pvalue +"'";
                    }
                } else {
                    sqlWhere += " WHERE " + id + "='" + pvalue +"'";
                }
            }
            if (StringUtil.isEmpty(sqlWhere) && "1".equals(pvalue)) {
                sqlWhere += " WHERE " + pid + "='" + pvalue +"'";
            }
        }
        String sqlSelect = getSelectSQl(bpmFormDialog);
        String isParent = ", ( case (select count(*)  from " + objName + " p where p." + pid + "=o." + id + " and p." + id + "!=p." + pid + ") when 0 then 'false' else 'true' end )isParent ";
        sqlSelect += isParent;
        List<DialogField> sortList = bpmFormDialog.getSortList();
        String orderBy = "";
        for (int i = 0; i < sortList.size(); i++) {
            DialogField df = sortList.get(i);
            if (i == 0) {
                orderBy = " order by ";
            }
            orderBy += df.getFieldName() + " " + df.getComment();
            if (i != sortList.size() - 1) {
                orderBy += ",";
            } else {
                sqlWhere += orderBy;
            }
        }
        String sql = "SELECT " + sqlSelect + " FROM " + objName + " o " + sqlWhere;
        return sql;
    }

    private DialogField getDailogField(FormDialog bpmFormDialog, String fieldname) throws Exception {
        TableModel tableModel;
        int istable = bpmFormDialog.getIstable();
        String dsName = bpmFormDialog.getDsalias();
        String objectName = bpmFormDialog.getObjname();
        // 表
        if (istable == 1) {
            BaseTableMeta meta = TableMetaFactory.getMetaData(dsName, dataSourceType);
            tableModel = meta.getTableByName(objectName);
        }
        // 视图处理
        else {
            IDbView dbView = TableMetaFactory.getDbView(dsName, dataSourceType);
            tableModel = dbView.getModelByViewName(objectName);
        }
        List<ColumnModel> columns = tableModel.getColumnList();
        for (ColumnModel column : columns) {
            if (column.getName().equalsIgnoreCase(fieldname)) {
                DialogField field = new DialogField();
                field.setComment(column.getComment());
                field.setFieldName(column.getName());
                field.setFieldType(column.getColumnType());
                return field;
            }
        }
        return null;
    }

    /**
     * 从DisplayField和ReturnField中取得Select字段，用于拼接SQL语句
     *
     * @param bpmFormDialog
     * @return
     */
    private String getSelectSQl(FormDialog bpmFormDialog) {
        String displayField = bpmFormDialog.getDisplayfield();
        JSONObject jsonObj = JSONObject.fromObject(displayField);
        String id = jsonObj.getString("id");
        String pid = jsonObj.getString("pid");
        String displayName = jsonObj.getString("displayName");
        List<DialogField> returnFields = bpmFormDialog.getReturnList();
        String sqlSelect = id + "," + pid + "," + displayName;
        for (DialogField field : returnFields) {
            String name = field.getFieldName();
            if (name.equalsIgnoreCase(id) || name.equalsIgnoreCase(pid) || name.equalsIgnoreCase(displayName)) {
                continue;
            }
            sqlSelect += "," + name;
        }
        return sqlSelect;
    }

    /**
     * 选择自定义对话框
     *
     * @return 自定义对话框list
     */
    public List<FormDialog> getAllDialogs() {
        Map<String, Object> map = new HashMap<>(16);
        map.put("style", 0);
        return formDialogDao.queryList(map);
    }
}
